03-15-24 (Friday)

Lord, you rule the world with a good and rightful code.
We ask for your wisdom to see things correctly and represent them faithfully.
Fill us with your justice so that we may know how to reflect it in the way we code,
Give us humility so that we may know the limits of our knowledge and its application in society,
Give us the courage to stand firmly when we feel pressured to go beyond these limits,
And give us responsibility as rulers we may be in the areas of society where you put us.

Lord, we want to reflect your good rule, so that people of all nations may fear your name.
Make known to us the path of life;
For in your presence there is fullness of joy;
and at your right hand are pleasures forevermore (Psalm 16).
Amen.

1 Quiz 04

2 Event handling

2.1 Example: turtle graphics

import turtle
screen = turtle.Screen()
pen = turtle.Turtle()
pen.penup()

def got_click(x, y):
    pen.goto(x, y)
    pen.write(
        f"Got click at {x}, {y}",
        font=("Arial", 12, "normal"))

screen.onclick(got_click)
screen.mainloop()
  • What is the object Screen?
  • What is the function onclick() doing? What is its argument? (Check the documentation)
  • See also the functions ondrag() (here), onkey() (here), etc

Some ideas - try to make it:

  • draw a person where you click
  • count how many times you clicked
  • say how long it’s been since the last click (use time.time())
  • switch it from screen.onclick to pen.onclick and have it go to a random location
  • keep track of the fastest click so far
  • have it record 10 clicks and show the average time it took
  • have the turtle walk by using WASD keys

2.2 Example: PyGame

import pygame 
pygame.init() 
  
# Creating window 
gameWindow = pygame.display.set_mode((800, 300)) 
pygame.display.set_caption("Event Handling") 

exit_game = False
game_over = False
  
# Creating a game loop 
while not exit_game: 
    for event in pygame.event.get():  # For Loop 
        if event.type == pygame.QUIT: 
            exit_game = True
  
        if event.type == pygame.KEYDOWN: 
            if event.key == pygame.K_RIGHT: 
                print("You have pressed right arrow key") 
            elif event.key == pygame.K_LEFT: 
                print("You have pressed left arrow key") 
  
pygame.quit() 
quit()

2.3 Definitions

  • Event handling is programming paradigm or pattern that involves capturing and responding to events that occur in a program. It typically has the following components:
  1. Event Source: The entity that generates or emits events. This could be a user action (like clicking a button or pressing a key) or some other system-generated event.
  2. Event Object: An object that represents the event and contains information about it, such as the type of event, the target element (if applicable), and any additional data.
  3. Event Listener (or Handler): A function or method that is registered to receive and respond to specific types of events. When an event occurs, the corresponding listener is invoked.
  4. Event Loop (or Dispatcher): The mechanism that manages the flow of events and dispatches them to the appropriate listeners. The event loop waits for events to occur and then triggers the corresponding listeners.
  5. Propagation: The process by which events are propagated or passed through the event hierarchy. For example, an event may be handled by the target element first and then propagated to its parent/child classes.

  • Event handling is commonly used in graphical user interfaces (GUIs) to respond to user interactions, but it can also be used in other types of applications to handle a wide range of events, such as network events, file system events, and timer events.

For the previous example (PyGame), ANSWER:

  • What are the event objects?
  • Where is the event loop?
  • Where are the event handlers?
  • Try to add an event that will trigger the variable exit_game to True. See PyGame events in this webpage.

3 Techniques and patterns with lists

3.1 List methods

From Python Documentation:

  • Take a look at methods you may find useful, and note them down here. Try to “play around” with them later.

3.2 Indexing and slicing

  • What will be printed at each step?
israelite_kings = ["Saul", "David", "Solomon", "Rehoboam", "Abijah", "Asa", "Jehoshaphat", "Jehoram", "Ahaziah", "Joash", "Amaziah", "Uzziah", "Jotham", "Ahaz", "Hezekiah", "Manasseh", "Amon", "Josiah", "Jehoahaz", "Jehoiakim", "Jehoiachin", "Zedekiah"]

print(israelite_kings[1])
print(israelite_kings[-2])
print(israelite_kings[3:5])
print(israelite_kings[:4])
print(israelite_kings[8:])
print(israelite_kings[3:10:3])
  • A list slice always return a copy of the list in question. (Check its ids with id(), for example).
    • That means that if we type israelite_kings[:], we are returning a complete copy of the list (the same as typing israelite_kings[:].copy())

3.3 Looping lists

  • There are basically two ways. Do you remember the difference?

    • When should we use one and when should we use the other?
    for king in israelite_kings:
      print(king)
    
    for ind in range(len(israelite_kings)):
      print(israelite_kings)
  • What does the function enumerate() does?

for ind, king in enumerate(israelite_kings):
  print(f'{ind+1}th king was {king}.')
  • What does the zip() function does? What does simply calling zip() returns?
kings = ["Saul", "David", "Solomon", "Rehoboam", "Jeroboam"]
nations = ["all Israel", "all Israel", "all Israel", "Judah", "north Israel"]
for k, n in zip(kings, nations):
  print(f'{k} ruled over {n}.')
  • What if I want to print sorted names?
for king in sorted(israelite_kings):
  print(king)
  • What is the different between the .sort() method and the sorted() method? (Hint: check the list objects).

  • Important: it is sometimes tempting to change a list while you are looping over it; however, you can run into lots of problems! It is often simpler and safer to create a new list instead.

    • For example, what is wrong in the following code?
for ind in range(len(israelite_kings)):
  israelite_kings.pop(ind)

3.4 Pattern: stacks

  • The following program is used to check if parentheses are matched.
def is_valid_parentheses(s):
    stack = []
    mapping = {')': '(', '}': '{', ']': '['}
    for char in s:
        if char in mapping.values():
            stack.append(char)
        elif char in mapping.keys():
            if not stack or mapping[char] != stack.pop():
                return False
        else:
            return False
    return len(stack) == 0
  • Notice the functions append() and pop()

  • Notice the boolean value that is being returned — the length of the stack should be zero if parentheses are matched

  • Try to use the function with some examples.

  • Can you think about a way of using a stack in programming? What examples from everyday life are stacks?

3.5 Queues

  • Another way to use lists is considering them as queues, instead of stacks.
    • Stacks are FIFO: First-In, First-Out
    • Queues are LIFO: Last-In, First-Out
  • Our event handlers, seen previously, can be understood as a queue. See the example:
# Initialize an empty event queue
event_queue = []

# Function to add an event to the queue
def add_event(event):
    event_queue.append(event)
    print(f"Event added: {event}")

# Add some events to the queue
add_event("Event 1")
add_event("Event 2")
add_event("Event 3")

# Process events from the queue
while len(event_queue) > 0:
  event = event_queue.pop(0)
  print(f"Processing event: {event}")
Event added: Event 1
Event added: Event 2
Event added: Event 3
Processing event: Event 1
Processing event: Event 2
Processing event: Event 3
  • What are other examples of queues - in programming and in everyday life?